use apikit::*;
use axum::{
    extract::{FromRequest, Request},
    response::IntoResponse,
};
use serde::de::DeserializeOwned;
use thiserror::Error;
use validator::SelfValidator;

use crate::{
    error::{BadRequest, EntityError, MapEntityError},
    param::Form,
};

use super::error_to_response;

#[derive(Debug, Error, ApiError)]
pub enum FormRejection {
    #[error(transparent)]
    Axum(#[from] EntityError),

    #[error(transparent)]
    Validate(#[from] BadRequest),
}

impl IntoResponse for FormRejection {
    fn into_response(self) -> axum::response::Response {
        error_to_response(self)
    }
}

impl<T, S> FromRequest<S> for Form<T>
where
    T: DeserializeOwned + SelfValidator + Send,
    S: Send + Sync,
{
    type Rejection = FormRejection;

    async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
        let data: T = axum::extract::Form::from_request(req, state)
            .await
            .map_entity_error()?
            .0;
        data.validate(None, None)
            .map_err(|e| BadRequest::from(e.to_string()))?;
        Ok(Self(data))
    }
}
